package com.rankeiot.core.sqltoy;

import org.sagacity.sqltoy.SqlToyContext;
import org.sagacity.sqltoy.config.model.EntityMeta;
import org.sagacity.sqltoy.config.model.FieldMeta;
import org.sagacity.sqltoy.dao.SqlToyLazyDao;
import org.sagacity.sqltoy.exception.DataAccessException;
import org.sagacity.sqltoy.utils.BeanUtil;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;

/**
 * SqlToyDao 方法扩展
 */
public interface DaoExt {
    /**
     * 获取 SqlToyLazyDao
     * @return
     */
    SqlToyLazyDao getDao();
    /**
     * 修改数据并返回数据库记录变更数量(非强制修改属性，当属性值为null或相等时不参与修改)
     *
     * @param origin 需要修改的原值,PK值必须要有
     * @param updated 需要更新的值,PK不必有值。需要修改的值不为null且不和原值相同
     * @param forceUpdateProps 如需将数据设置为null,forceUpdateProps中写入属性名
     * @return Long 数据库记录变更量(插入数据量)
     */
    default <T extends Serializable> Long update(T origin, T updated, String ...forceUpdateProps){
        SqlToyLazyDao dao=getDao();
        final Class beanType=origin.getClass();
        Set<String> fu=new HashSet<>(Arrays.asList(forceUpdateProps));
        SqlToyContext sqlToyContext= dao.getSqlToyContext();
        EntityMeta meta= sqlToyContext.getEntityMeta(origin.getClass());
        StringBuilder sb=new StringBuilder("update "+meta.getTableName()+" set ");
        List<String> sets=new ArrayList<>();
        for(FieldMeta fm : meta.getFieldsMeta().values()){
            String name=fm.getFieldName();
            try {
                Field field=beanType.getDeclaredField(name);
                field.setAccessible(true);
                if(fm.isPK()){
                    Object v= field.get(origin);
                    if(v==null){
                        throw new DataAccessException("更新时,目标主键不能为空");
                    }
                    field.set(updated,v);
                }else{
                    Object nv=field.get(updated);
                    if(nv==null&&!fu.contains(name)){
                        continue;
                    }
                    Object oldV=field.get(origin);
                    if(Objects.equals(nv,oldV)){
                        continue;
                    }
                    sets.add(fm.getColumnName()+"=:"+name);
                }
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        if(sets.size()==0){
            return 0L;
        }
        sb.append(String.join(",",sets));
        sb.append(meta.getIdNameWhereSql());
        return dao.executeSql(sb.toString(),updated);
    }
    /**
     * 修改数据并返回数据库记录变更数量(当属性值相等时不参与修改)
     *
     * @param origin 需要修改的原值,PK值必须要有
     * @param updated 需要更新的值,PK不必有值。需要修改的值不和原值相同即可更新
     * @return Long 数据库记录变更量(插入数据量)
     */
    default Long update(Serializable origin,Map<String,Object> updated){
        final Class beanType=origin.getClass();
        SqlToyLazyDao dao=getDao();
        SqlToyContext sqlToyContext= dao.getSqlToyContext();
        EntityMeta meta= sqlToyContext.getEntityMeta(origin.getClass());
        StringBuilder sb=new StringBuilder("update "+meta.getTableName()+" set ");
        List<String> sets=new ArrayList<>();
        for(FieldMeta fm : meta.getFieldsMeta().values()){
            String name=fm.getFieldName();
            try {
                Field field=beanType.getDeclaredField(name);
                field.setAccessible(true);
                if(fm.isPK()){
                    Object v= field.get(origin);
                    if(v==null){
                        throw new DataAccessException("更新时,目标主键不能为空");
                    }
                    updated.put(name,v);
                    // field.set(updated,v);
                }else{
                    Object nRv=updated.get(name);
                    if(nRv==null){
                        continue;
                    }
                    Object nv= BeanUtil.convertType(nRv,fm.getType(),field.getType().getName());
                    if(nv==null){
                        continue;
                    }
                    Object oldV=field.get(origin);
                    if(Objects.equals(nv,oldV)){
                        continue;
                    }
                    sets.add(fm.getColumnName()+"=:"+name);
                }
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if(sets.size()==0){
            return 0L;
        }
        sb.append(String.join(",",sets));
        sb.append(meta.getIdNameWhereSql());
        return dao.executeSql(sb.toString(),updated);
    }
}
